package service

import (
	"fmt"
	"gorm.io/gorm"
	"path"
	"shop-bean/constant"
	"shop-bean/model"
	"shop-common/library/loggerV2"
	"shop-common/library/variables"
	"shop-common/utils/moment"
	"shop-common/utils/uploader"
	"shop-service/repository"
	"strconv"
	"strings"
	"time"
)

type IFileService interface {
	//FindFile()
	Create(file *model.File) error
	Upload(userId uint, validFile *uploader.FileRequest) (*uploader.FileResponse, error)
	UploadChunk(request *uploader.ShardFileRequest) (*uploader.ShardFileResponse, error)
	FindExpireFiles() error
}

type FileService struct {
	db         *gorm.DB
	repository repository.IFileRepository
}

func NewFileService() IFileService {
	return &FileService{
		db:         variables.GormDB(),
		repository: repository.NewFileRepository(),
	}
}

func (s *FileService) Create(file *model.File) error {
	return s.db.Model(&model.File{}).Create(&file).Error
}

//普通附件上传，默认状态 24小时过期。
func (s *FileService) Upload(userId uint, validFile *uploader.FileRequest) (*uploader.FileResponse, error) {
	vo, err := uploader.GetDefaultStorage().Put(validFile)
	if err != nil {
		loggerV2.Error(err)
		return nil, err
	}

	entity := &model.File{
		Id:           0,
		RealName:     vo.RealName,
		Name:         vo.Name,
		LocationType: vo.LocationType,
		UserId:       userId,
		AttDir:       vo.AttDir,
		AttSize:      vo.AttSize,
		AttType:      vo.AttType,
		ContentType:  vo.ContentType,
		Hash:         vo.Hash,
		Bucket:       vo.Bucket,
		Key:          vo.Key,
		Status:       constant.FILE_FINITUDE,
	}

	if err := variables.GormDB().Create(&entity).Error; err != nil {
		loggerV2.Error(err)
		return nil, err
	}

	return &uploader.FileResponse{
		Status:         uploader.FileSuccess,
		FileId:         entity.Id,
		Path:           validFile.NewFileName,
		Name:           validFile.NewFileName,
		Url:            strings.Join([]string{uploader.GetHostStatic(vo.LocationType), vo.AttDir, vo.Name}, ""),
		Code:           0,
		FileFormerName: vo.RealName,
	}, nil

}

func (s *FileService) UploadChunk(request *uploader.ShardFileRequest) (*uploader.ShardFileResponse, error) {
	var dataAt string
	if request.UniqAt != "" {
		toTime, err := moment.StringConverToTime(request.UniqAt)
		if err != nil || toTime == nil {
			fmt.Println("最新时间")
			dataAt = time.Now().Format("2006/01/02")
		} else {
			dataAt = toTime.Format("2006/01/02")
		}
	} else {
		dataAt = time.Now().Format("2006/01/02")
	}

	put, err := uploader.NewLocalUploader().Put(&uploader.FileRequest{
		RealName:    request.Filename,
		NewFileName: request.Filename + "_" + strconv.Itoa(int(request.ChunkNumber)),
		FileStream:  request.FileByte,
		StreamSize:  int(request.ActualChunkSize),
		Name:        request.Filename + "_" + strconv.Itoa(int(request.ChunkNumber)),
		FileType:    "video/mp4",
		AttDir:      path.Join(dataAt, request.Hash) + "/",
	})

	if request.ChunkNumber == request.TotalChunks {
		result, err := uploader.MergeChunks(request)
		if err != nil {
			loggerV2.Fatal(err)
		}
		return result, nil
	}

	return &uploader.ShardFileResponse{
		Code:   1,
		Url:    "",
		FileVO: put,
	}, err
}

func (s *FileService) FindExpireFiles() error {
	files, err := s.repository.FindExpireFile(s.db)
	if err != nil {
		loggerV2.Error(err)
		return err
	}

	if len(files) == 0 {
		return nil
	}
	err = s.DeleteBatchExpire(files)
	if err != nil {
		loggerV2.Error(err)
		return err
	}

	return nil
}

func (s *FileService) DeleteBatchExpire(rows []*model.File) error {
	var ids []uint
	var qiniuFilePath []string
	var localFilePath []string

	for _, row := range rows {
		ids = append(ids, row.Id)

		if row.LocationType == uploader.LOCAL_TYPE_ATTACHMENT {
			localFilePath = append(localFilePath, row.AttDir+row.Name)
		} else if row.LocationType == uploader.QINIU_TYPE_ATTACHMENT {
			qiniuFilePath = append(qiniuFilePath, row.Name)
		}
	}

	err := s.repository.DeleteBatch(s.db, ids)
	if err != nil {
		loggerV2.Error(err)
		return err
	}

	if localFilePath != nil && len(localFilePath) > 0 {
		err = uploader.GetManualStorage(constant.LOCAL_TYPE_ATTACHMENT).BucketDelete(localFilePath...)
	}

	if qiniuFilePath != nil && len(qiniuFilePath) > 0 {
		err = uploader.GetManualStorage(constant.QINIU_TYPE_ATTACHMENT).BucketDelete(qiniuFilePath...)
	}

	return nil
}
